﻿using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SocialFront.Core.Services.Application.Concrete;
using SocialFront.Core.Repository.EF.Repositories;
using SocialFront.Core.Domain.Concrete;
using SocialFront.Core.Services.Application.Messaging.Requests;

namespace SocialFront.Tests
{
    [TestClass]
    public class FooStoreTests
    {
        private FooService service = new FooService(new EFStore());

        [TestMethod]
        public void CanPerformWildCardSearch()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "aXyZ3XiaazdfdazIaVaDuMFoo", Foo2 = "NewFoo2" };
            CreateFoo(foo);
            service.Store.Dispose();

            Foo wildcardFoo = new Foo() { Foo1 = "aXyZ3" };
            GetRequestBase<Foo> wildcardRequest = new FooWildcardSearchListRequest() { Entity = wildcardFoo };

            // Important - if for some reason this stupid string gets in the database, this test will fail.
            // So it's probably better to Moq the store soon so the test space can be guaranteed this string
            // never gets in the data store.
            Foo badwildcardFoo = new Foo() { Foo1 = "zzzzzzxxxxxxdddddddddd" };
            GetRequestBase<Foo> badWildcardRequest = new FooWildcardSearchListRequest() { Entity = badwildcardFoo };

            // Act
            Foo fooTarget    = service.GetBy(wildcardRequest).Entity;
            Foo badFooTarget = service.GetBy(badWildcardRequest).Entity;
            
            // Assert 
            Assert.IsNotNull(fooTarget);
            Assert.IsNull(badFooTarget);

            // Clean up...
            DeleteFoo(foo);
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanPerformExactSearch()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "myexactsearchfootest" };
            CreateFoo(foo);
            service.Store.Dispose();

            Foo exactFoo = new Foo() { Foo1 = "myexactsearchfootest" };
            GetRequestBase<Foo> exactSearchRequest = new FooExactListRequest() { Entity = exactFoo };

            // Important - if for some reason this stupid string gets in the database, this test will fail.
            // So it's probably better to Moq the store soon so the test space can be guaranteed this string
            // never gets in the data store.
            Foo badexactFoo = new Foo() { Foo1 = "myexactsearchfootest12" };
            GetRequestBase<Foo> badExactFooRequest = new FooExactListRequest() { Entity = badexactFoo };

            // Act
            Foo fooTarget    = service.GetBy(exactSearchRequest).Entity;
            Foo badFooTarget = service.GetBy(badExactFooRequest).Entity;

            // Assert 
            Assert.IsNotNull(fooTarget);
            Assert.IsNull(badFooTarget);

            // Clean up...
            DeleteFoo(fooTarget);
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanInsertNewFooWithNoChildlren()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "NewFoo", Foo2 = "NewFoo2" };

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = foo };

            // Act
            service.CreateBy(request);
            service.Store.SaveChanges();
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert 
            Assert.AreEqual(foo, fooCopy);
            Assert.AreEqual(null, foo.Siblings);
            Assert.AreEqual(0, fooCopy.Siblings.Count); // <-- When you come back fresh with virtual proxies, you get an empty list, not null ?   

            // Clean up...
            service.Store.Delete<Foo>(fooCopy);
            service.Store.SaveChanges();
        }

        [TestMethod]
        public void CanInsertNewFooWithChildren()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "NewFoo", Foo2 = "NewFoo2" };

            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child3" });  

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = foo };

            // Act
            service.CreateBy(request);
            service.Store.SaveChanges();
            service.Store.Dispose();

            // Assert 
            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;
            Assert.AreEqual(foo, fooCopy);
            Assert.AreEqual(3, fooCopy.Siblings.Count);

            // Clean up...
            service.Store.Delete<Foo>(fooCopy);
            service.Store.SaveChanges();
        }

        [TestMethod]
        public void CanUpdateFooWithNoChildren()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };
            CreateFoo(foo);
            service.Store.Dispose();

            // Act
            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Foo1 = "update1";
            fooView.Foo2 = "update2";

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooView };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert
            Assert.AreEqual("update1", fooCopy.Foo1);
            Assert.AreEqual("update2", fooCopy.Foo2);

            // Clean up
            DeleteFoo(fooCopy);
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanUpdateFooScalarsAndComplexTypes() 
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1", Foo2 = "Foo2" };
            foo.FooDetailComplex.FooDetailComplexProp  = "FooDetail1";
            foo.FooDetailComplex.FooDetailComplexProp2 = "FooDetail2";
            CreateFoo(foo);
            service.Store.Dispose();

            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Siblings = new List<FooSibling>();
            fooView.Siblings.Add(new FooSibling() { FooId = fooView.Id, SiblingPropFoo = "child1" });
            fooView.Siblings.Add(new FooSibling() { FooId = fooView.Id, SiblingPropFoo = "child2" });

            // Act
            fooView.Foo1 = "update1";
            fooView.Foo2 = "update2";
            fooView.FooDetailComplex.FooDetailComplexProp  = "FooDetailUpdate1";
            fooView.FooDetailComplex.FooDetailComplexProp2 = "FooDetailUpdate2";

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooView };
            service.UpdateBy(request);
            service.Store.SaveChanges();
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert
            Assert.AreEqual("update1", fooCopy.Foo1);
            Assert.AreEqual("update2", fooCopy.Foo2);
            Assert.AreEqual("FooDetailUpdate1", fooCopy.FooDetailComplex.FooDetailComplexProp);
            Assert.AreEqual("FooDetailUpdate2", fooCopy.FooDetailComplex.FooDetailComplexProp2);

            // Clean up
            DeleteFoo(fooCopy);
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanUpdateFooWithNewChildren()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };
            CreateFoo(foo);
            service.Store.Dispose();

            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Siblings = new List<FooSibling>();
            fooView.Siblings.Add(new FooSibling() { FooId = fooView.Id, SiblingPropFoo = "child1" });
            fooView.Siblings.Add(new FooSibling() { FooId = fooView.Id, SiblingPropFoo = "child2" });

            // Act
            fooView.Foo1 = "update1";
            fooView.Foo2 = "update2";

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooView };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert
            Assert.AreEqual("update1", fooCopy.Foo1);
            Assert.AreEqual("update2", fooCopy.Foo2);
            Assert.AreEqual(2, fooCopy.Siblings.Count);
            Assert.AreEqual("child1", fooCopy.Siblings[0].SiblingPropFoo);
            Assert.AreEqual("child2", fooCopy.Siblings[1].SiblingPropFoo);

            // Clean up
            DeleteFoo(fooCopy);
            service.Store.Dispose();
        }
        
        // Inspect.
        [TestMethod]
        public void CanUpdateFooWithModifiedChildren()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };
            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child2" });

            foo.FooDetailComplex.FooDetailComplexProp  = "Complex1";
            foo.FooDetailComplex.FooDetailComplexProp2 = "Complex2";
        
            CreateFoo(foo);
            service.Store.Dispose();

            // Act
            Foo fooCopy = new Foo() { Id = foo.Id };

            fooCopy.Foo1 = "update1";
            fooCopy.Foo2 = "update2";

            fooCopy.Siblings = new List<FooSibling>();
            fooCopy.Siblings.Add(new FooSibling { FooId = foo.Id, Id = foo.Siblings[0].Id });
            fooCopy.Siblings.Add(new FooSibling { FooId = foo.Id, Id = foo.Siblings[1].Id });
            fooCopy.Siblings[0].SiblingPropFoo = "childupdate1";
            fooCopy.Siblings[1].SiblingPropFoo = "childupdate2";

            fooCopy.FooDetailComplex.FooDetailComplexProp  = "Complex1Update";
            fooCopy.FooDetailComplex.FooDetailComplexProp2 = "Complex2Update";

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooCopy };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            // Assert
            Foo fooCopyCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            Assert.AreEqual("update1", fooCopyCopy.Foo1);
            Assert.AreEqual("update2", fooCopyCopy.Foo2);
            Assert.AreEqual(2, fooCopyCopy.Siblings.Count);
            Assert.AreEqual("childupdate1", fooCopyCopy.Siblings[0].SiblingPropFoo);
            Assert.AreEqual("childupdate2", fooCopyCopy.Siblings[1].SiblingPropFoo);
            Assert.AreEqual("Complex1Update", fooCopyCopy.FooDetailComplex.FooDetailComplexProp);
            Assert.AreEqual("Complex2Update", fooCopyCopy.FooDetailComplex.FooDetailComplexProp2);

            // Clean up
            service.Store.Delete(fooCopy);
            service.Store.SaveChanges();
        }

        // Inspect.
        [TestMethod]
        public void CanUpdateFooWithChildrenToBeDeleted()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };
            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child3" });
            CreateFoo(foo);
            service.Store.Dispose();

            // Act
            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Foo1 = "update1";
            fooView.Foo2 = "update2";
            fooView.Siblings = new List<FooSibling>();
            fooView.Siblings.Add(foo.Siblings[2]);
            //fooView.Siblings.Add(new FooSibling() { FooId = foo.Id, Id = foo.Siblings[2].Id });
            fooView.Siblings[0].SiblingPropFoo = "child4";

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooView };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = fooView }).Entity;

            // Assert
            Assert.AreEqual("update1", fooCopy.Foo1);
            Assert.AreEqual("update2", fooCopy.Foo2);
            Assert.AreEqual(1, fooCopy.Siblings.Count);
            Assert.AreEqual("child4", fooCopy.Siblings[0].SiblingPropFoo);

            // Clean up
            service.Store.Delete(fooCopy);
            service.Store.SaveChanges();
        }

        [TestMethod]
        public void CanDeleteFooAndAllItsChildren()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "NewFoo", Foo2 = "NewFoo2" };

            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child3" });

            CreateFoo(foo);
            service.Store.Dispose();

            var id = foo.Id;
            var siblingId1 = foo.Siblings[0].Id;
            var siblingId2 = foo.Siblings[1].Id;
            var siblingId3 = foo.Siblings[2].Id;
           
            // Act
            FooDeleteRequest deleteRequest = new FooDeleteRequest() { Entity = foo };
            service.DeleteBy(deleteRequest);
            service.Store.SaveChanges();
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest() { Entity = new Foo() { Id = id } }).Entity;

            FooSibling sibling1 = service.Store.FirstOrDefault<FooSibling>(x => x.Id == siblingId1);
            FooSibling sibling2 = service.Store.FirstOrDefault<FooSibling>(x => x.Id == siblingId2);
            FooSibling sibling3 = service.Store.FirstOrDefault<FooSibling>(x => x.Id == siblingId3);
           
            // Assert 
            Assert.AreEqual(null, fooCopy);
            Assert.AreEqual(null, sibling1);
            Assert.AreEqual(null, sibling2);
            Assert.AreEqual(null, sibling3);
        }

        [TestMethod]
        public void CanWildcardDeleteFoo()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "Delete", Foo2 = "Delete" };

            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child2" });

            CreateFoo(foo);
            service.Store.Dispose();

            var id = foo.Id;
            var siblingId1 = foo.Siblings[0].Id;
            var siblingId2 = foo.Siblings[1].Id;

            Foo foo2 = new Foo { Foo1 = "Delete", Foo2 = "DeleteXX" };
            CreateFoo(foo2);
            service.Store.Dispose();

            Foo foo3 = new Foo { Foo1 = "DontDelete", Foo2 = "DontDelete" };
            CreateFoo(foo3);
            service.Store.Dispose();

            Foo foo4 = new Foo { Foo1 = "Delete", Foo2 = "Delete" };
            CreateFoo(foo4);
            service.Store.Dispose();

            // Set up a foo to dictate we want to delete all foos and its children if 
            // and only if Foo1 and Foo2 are both equal to delete.
            Foo fooDeleteModel = new Foo { Foo1 = "Delete", Foo2 = "Delete" };

            // Act
            DeleteRequestBase<Foo> deleteRequest = new FooWildcardDeleteRequest() { Entity = fooDeleteModel };
            service.DeleteBy(deleteRequest);
            service.Store.SaveChanges();
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest() { Entity = new Foo() { Id = id } }).Entity;

            FooSibling sibling1 = service.Store.FirstOrDefault<FooSibling>(x => x.Id == siblingId1);
            FooSibling sibling2 = service.Store.FirstOrDefault<FooSibling>(x => x.Id == siblingId2);

            Foo fooCopy2 = service.GetBy(new FooIdSearchRequest() { Entity = new Foo() { Id = foo2.Id } }).Entity;
            Foo fooCopy3 = service.GetBy(new FooIdSearchRequest() { Entity = new Foo() { Id = foo3.Id } }).Entity;
            Foo fooCopy4 = service.GetBy(new FooIdSearchRequest() { Entity = new Foo() { Id = foo4.Id } }).Entity;

            // Assert 
            Assert.IsNull(fooCopy);
            Assert.IsNull(sibling1);
            Assert.IsNull(sibling2);

            Assert.IsNotNull(fooCopy2);
            Assert.IsNotNull(fooCopy3);
            Assert.IsNull(fooCopy4);

            // Clean up the two foos that didn't get whacked.
            DeleteFoo(fooCopy2);
            DeleteFoo(fooCopy3);
        }

        private void CreateFoo(Foo foo)
        {
            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = foo };
            service.CreateBy(request);
            service.Store.SaveChanges();
        }

        private void DeleteFoo(Foo foo)
        {
            service.Store.Delete<Foo>(foo);
            service.Store.SaveChanges();
        }

        // Foo Sibling Sibling 
        [TestMethod]
        public void CanInsertNewFooWithChildrenWithChildren()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "NewFoo", Foo2 = "NewFoo2" };

            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child3" });

            foo.Siblings[0].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild1" });
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild2" });

            foo.Siblings[1].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild1" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild2" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild3" });

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = foo };

            // Act
            service.CreateBy(request);
            service.Store.Dispose();

            // Assert 
            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;
            Assert.AreEqual(foo, fooCopy);
            Assert.AreEqual(3, fooCopy.Siblings.Count);
            Assert.AreEqual(foo.Siblings[0].Siblings.Count, 2);
            Assert.AreEqual(foo.Siblings[1].Siblings.Count, 3);

            // Clean up...must kill all foosiblingsiblings first...they do not cascade on delete.  
            foo.Siblings[0].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            foo.Siblings[1].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            service.Store.Delete<Foo>(fooCopy);
            service.Store.SaveChanges();
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanDeleteFooWithChildrenWithChildren()
        {
            // Arrange
            Foo foo = new Foo { Foo1 = "NewFoo", Foo2 = "NewFoo2" };

            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "Child3" });

            foo.Siblings[0].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild1" });
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild2" });

            foo.Siblings[1].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild1" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild2" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "ChildChild3" });

            CreateFoo(foo);
            service.Store.Dispose();

            List<long> ids = new List<long>();
            ids.Add(foo.Siblings[0].Siblings[0].Id);
            ids.Add(foo.Siblings[0].Siblings[1].Id);

            ids.Add(foo.Siblings[1].Siblings[0].Id);
            ids.Add(foo.Siblings[1].Siblings[1].Id);
            ids.Add(foo.Siblings[1].Siblings[2].Id);

            // Act
            FooDeleteRequest deleteRequest = new FooDeleteRequest() {  Entity = new Foo() { Id = foo.Id } };
            service.DeleteFooGraphBy(deleteRequest);
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert 
            Assert.AreEqual(fooCopy, null);

            // Ensure relationships were wiped out.
            ids.ForEach(id => Assert.AreEqual(null, service.Store.FirstOrDefault<FooSiblingSibling>(x => x.Id == id).FooSiblingId));

            // Clean up
            foo.Siblings[0].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            foo.Siblings[1].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            service.Store.SaveChanges();
        }

        // 3-Level Deep Tests
        [TestMethod]
        public void CanUpdateFooWithModifiedChildren_3Levels()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };

            // create 2nd level.  
            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child2" });

            // create 3rd level. 
            foo.Siblings[0].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo  = "grandchild1" });
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild2" });


            foo.Siblings[1].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild3" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild4" });

            CreateFoo(foo);
            service.Store.Dispose();

            // Act
            Foo fooCopy = new Foo() { Id = foo.Id };

            // Update Level 1
            fooCopy.Foo1 = "update1";
            fooCopy.Foo2 = "update2";

            // Update Level 2
            fooCopy.Siblings = new List<FooSibling>();
            fooCopy.Siblings.Add(new FooSibling() { FooId = foo.Id, Id = foo.Siblings[0].Id, SiblingPropFoo = "childupdate1" });
            fooCopy.Siblings.Add(new FooSibling() { FooId = foo.Id, Id = foo.Siblings[1].Id, SiblingPropFoo = "childupdate2" });

            // Update Level 3  
            fooCopy.Siblings[0].Siblings = new List<FooSiblingSibling>();
            fooCopy.Siblings[0].Siblings.Add(new FooSiblingSibling() { FooSiblingId = foo.Siblings[0].Id, Id = foo.Siblings[0].Siblings[0].Id, SiblingSiblingPropFoo = "grandchildupdate1" });
            fooCopy.Siblings[0].Siblings.Add(new FooSiblingSibling() { FooSiblingId = foo.Siblings[0].Id, Id = foo.Siblings[0].Siblings[1].Id, SiblingSiblingPropFoo = "grandchildupdate2" });

            fooCopy.Siblings[1].Siblings = new List<FooSiblingSibling>();
            fooCopy.Siblings[1].Siblings.Add(new FooSiblingSibling() { FooSiblingId = foo.Siblings[1].Id, Id = foo.Siblings[1].Siblings[0].Id, SiblingSiblingPropFoo = "grandchildupdate3" });
            fooCopy.Siblings[1].Siblings.Add(new FooSiblingSibling() { FooSiblingId = foo.Siblings[1].Id, Id = foo.Siblings[1].Siblings[1].Id, SiblingSiblingPropFoo = "grandchildupdate4" });

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooCopy };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            Foo fooReCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert
            Assert.AreEqual("update1", fooReCopy.Foo1);
            Assert.AreEqual("update2", fooReCopy.Foo2);
            Assert.AreEqual(2, fooReCopy.Siblings.Count);
            Assert.AreEqual("childupdate1", fooReCopy.Siblings[0].SiblingPropFoo);
            Assert.AreEqual("childupdate2", fooReCopy.Siblings[1].SiblingPropFoo);
            Assert.AreEqual(2, fooReCopy.Siblings[0].Siblings.Count);
            Assert.AreEqual("grandchildupdate1", fooReCopy.Siblings[0].Siblings[0].SiblingSiblingPropFoo);
            Assert.AreEqual("grandchildupdate2", fooReCopy.Siblings[0].Siblings[1].SiblingSiblingPropFoo);
            Assert.AreEqual(2, fooReCopy.Siblings[1].Siblings.Count);
            Assert.AreEqual("grandchildupdate3", fooReCopy.Siblings[1].Siblings[0].SiblingSiblingPropFoo);
            Assert.AreEqual("grandchildupdate4", fooReCopy.Siblings[1].Siblings[1].SiblingSiblingPropFoo);

            // Clean up
            foo.Siblings[0].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            foo.Siblings[1].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            DeleteFoo(fooReCopy);
            service.Store.Dispose();
        }

        // Inspect.
        [TestMethod]
        public void CanUpdateFooWithChildrenAndGrandchildrenToBeDeleted()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "Foo1" };
            
            // Create 2nd level. 
            foo.Siblings = new List<FooSibling>();
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child1" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child2" });
            foo.Siblings.Add(new FooSibling() { SiblingPropFoo = "child3" });

            // Create 3rd level. 
            // create 3rd level. 
            foo.Siblings[0].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild1" });
            foo.Siblings[0].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild2" });

            foo.Siblings[1].Siblings = new List<FooSiblingSibling>();
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild3" });
            foo.Siblings[1].Siblings.Add(new FooSiblingSibling() { SiblingSiblingPropFoo = "grandchild4" });

            CreateFoo(foo);
            service.Store.Dispose();

            // Act
            Foo fooView = new Foo() { Id = foo.Id };

            // Update level 1
            fooView.Foo1 = "update1";
            fooView.Foo2 = "update2";

            // update level 2  
            fooView.Siblings = new List<FooSibling>();
            fooView.Siblings.Add(new FooSibling() { FooId = foo.Id, SiblingPropFoo = "child2update" });

            // update level 3 
            fooView.Siblings[0].Siblings = new List<FooSiblingSibling>();
            fooView.Siblings[0].Siblings.Add(new FooSiblingSibling() { FooSiblingId = foo.Siblings[0].Id, SiblingSiblingPropFoo = "grandchildupdate" });

            RequestBase<Foo> request = new RequestBase<Foo>() { Entity = fooView };
            service.UpdateFooGraphBy(request);
            service.Store.Dispose();

            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;

            // Assert
            Assert.AreEqual("update1", fooCopy.Foo1);
            Assert.AreEqual("update2", fooCopy.Foo2);
            Assert.AreEqual(1, fooCopy.Siblings.Count);
            Assert.AreEqual("child2update", fooCopy.Siblings[0].SiblingPropFoo);
            Assert.AreEqual(1, fooCopy.Siblings[0].Siblings.Count);
            Assert.AreEqual("grandchildupdate", fooCopy.Siblings[0].Siblings[0].SiblingSiblingPropFoo);

            // Clean up
            foo.Siblings[0].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            foo.Siblings[1].Siblings.ToList().ForEach(x => service.Store.Delete(x));
            fooView.Siblings[0].Siblings.ToList().ForEach(x => service.Store.Delete(x));

            DeleteFoo(fooCopy);
            service.Store.Dispose();
        }

        [TestMethod]
        public void CanAddLocationsToFoo()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "My Foo"};
            CreateFoo(foo);
            service.Store.Dispose();

            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Locations = new List<Location>();
            fooView.Locations.Add(new Location() { LocationCode = "AAA55" });
            fooView.Locations.Add(new Location() { LocationCode = "55Bz3s"});

            // Act
            service.UpdateFooGraphBy(new RequestBase<Foo>() { Entity = fooView});
            service.Store.Dispose();

            // Assert
            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;
            Assert.AreEqual(2, fooCopy.Locations.Count);
            Assert.AreEqual("AAA55", fooCopy.Locations[0].LocationCode);
            Assert.AreEqual("55Bz3s", fooCopy.Locations[1].LocationCode);
        }

        [TestMethod]
        public void CanRemoveLocationsFromFoo()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "My Foo" };
            foo.Locations = new List<Location>();
            foo.Locations.Add(new Location() { LocationCode = "AAA55" });
            foo.Locations.Add(new Location() { LocationCode = "55Bz3s" });
            CreateFoo(foo);
            service.Store.Dispose();

            Foo fooView = new Foo() { Id = foo.Id };
            fooView.Locations = new List<Location>();
            fooView.Locations.Add(foo.Locations[1]);

            // Act
            service.UpdateFooGraphBy(new RequestBase<Foo>() { Entity = fooView });
            service.Store.Dispose();

            // Assert
            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;
            Assert.AreEqual(1, fooCopy.Locations.Count);
            Assert.AreEqual("55Bz3s", fooCopy.Locations[0].LocationCode);
        }

        [TestMethod]
        public void CanDeleteFooWithLocations()
        {
            // Arrange
            Foo foo = new Foo() { Foo1 = "My Foo" };
            foo.Locations = new List<Location>();
            foo.Locations.Add(new Location() { LocationCode = "AAA55" });
            foo.Locations.Add(new Location() { LocationCode = "55Bz3s" });
            CreateFoo(foo);
            service.Store.Dispose();

            Foo fooView = new Foo() { Id = foo.Id };

            // Act
            service.DeleteBy(new FooDeleteRequest() { Entity = fooView });
            service.Store.Dispose();

            // Assert
            Foo fooCopy = service.GetBy(new FooIdSearchRequest { Entity = foo }).Entity;
            Assert.AreEqual(null, fooCopy);

            var location = service.Store.FirstOrDefault<Location>(x => x.Foos.Any(f => f.Id == foo.Id));
            Assert.IsNull(location);
        }
    }
}